<?php

namespace dousdk;

use commonsdk\Tools;
use commonsdk\Video_range;
use think\facade\Db;
use think\exception\HttpResponseException;

class AuthAppDouyin {

    const URL_CONNECT = 'https://open.douyin.com/platform/oauth/connect';
    const URL_TOKEN = 'https://open.douyin.com/oauth/access_token';
    const URL_REFRESH_TOKEN = 'https://open.douyin.com/oauth/refresh_token/';
    const URL_REFRESH_REFRESH_TOKEN = 'https://open.douyin.com/oauth/renew_refresh_token/';
    const URL_USER_INFO = 'https://open.douyin.com/oauth/userinfo/';
    const URL_USER_FANS_LIST = 'https://open.douyin.com/fans/list/';
    const URL_USER_FOLLOW_LIST = 'https://open.douyin.com/following/list/';
    const URL_VIDEO_LIST = 'https://open.douyin.com/video/list/';
    const URL_VIDEO_DATA = 'https://open.douyin.com/video/data/';
    const URL_VIDEO_UPLOAD = 'https://open.douyin.com/video/upload/';
    const URL_VIDEO_UPLOAD_PART_INIT = 'https://open.douyin.com/video/part/init/';
    const URL_VIDEO_UPLOAD_PART_UPLOAD = 'https://open.douyin.com/video/part/upload/';
    const URL_VIDEO_UPLOAD_PART_COMPLETE = 'https://open.douyin.com/video/part/complete/';
    const URL_VIDEO_CREATE = 'https://open.douyin.com/video/create/';
    
    const URL_VIDEO_INFO = 'https://open.douyin.com/data/external/item/base/';

    static public $scopes = [
        //视频权限
        'aweme.share', //抖音分享
        'video.create',
        'video.delete',
        'video.data',
        'video.list',
        //        'toutiao.video.create',
        //        'toutiao.video.data',
        //        'xigua.video.data',
        //        'xigua.video.create',
        //'im. share',
        //'video.search',
        //'video.search.comment',
        //用户权限
        'user_info',
            //'following.list',
            //'fans.list',
            //'login_id',
            // 'renew_refresh_token',
            //'mobile_alert',
            //互动权限
            //'video.comment', //企业号评论
            //'im', //企业私信
            //'item.comment',
            //数据权限
            // 'hotsearch',
            // 'fans.data',
            // 'data.external.user',
            //'data.external.item',
            //'star_top_score_display',
            //'star_tops',
            //'star_author_score_display',
            //'data.external.sdk_share',
            //特殊权限
            //'share_with_source',
            //'poi.search',
            //'micapp.is_legal',
    ];
    public $client_key;
    public $client_secret;

    public function __destruct() {
        
    }
    
    
    
    public function get_video_info($access_token,$open_id,$item_id)
    {
         $arr = [
            'access_token' => $access_token,
            'open_id' => $open_id,
            'item_id'=>$item_id
        ];
        $response = file_get_contents(self::URL_VIDEO_INFO . '?' . http_build_query($arr));
        $data = self::checkResponse($response);
        return $data;
    }

    /**
     * 通过网页授权获取粉丝信息
     */
    public function getWebOauthInfo($redirects, $redirect = true): array {
        if (input('get.code') == "") {
            $oauthurl = self::buildConnectUrl($redirects);
           // echo $oauthurl;exit;
            if ($redirect) {
                throw new HttpResponseException(redirect($oauthurl, 302));
            } else {
                throw new HttpResponseException(response("window.location.href='{$oauthurl}'"));
            }
        }
        if (($token_arr = $this->getTokenByCode(input('get.code')))) {
            $fansinfo = self::getAuthUserInfo($token_arr['access_token'], $token_arr['open_id']);
            $fansinfo['access_token'] = $token_arr['access_token'];
            return $fansinfo;
        }
    }

    //创建授权跳转链接  获取code
    public function buildConnectUrl($redirect = "") {
        $arr = [
            'client_key' => $this->client_key,
            'scope' => implode(',', self::$scopes),
            'redirect_uri' => $redirect,
            'response_type' => 'code',
            'state' => "",
        ];
        return self::URL_CONNECT . '?' . http_build_query($arr);
    }

    //刷新refresh_token
    public function refreshRefreshToken($authAccount) {
        $arr = [
            'client_key' => $this->client_key,
            'refresh_token' => $authAccount['refresh_token'],
        ];
        $response = file_get_contents(self::URL_REFRESH_REFRESH_TOKEN . '?' . http_build_query($arr));
        $data = self::checkResponse($response);
        $authAccount['refresh_token'] = $data['refresh_token'];
        $authAccount['refresh_expires_in'] = $data['refresh_expires_in'];
        if (!Db::name('dy_accesstoken')->update($authAccount)) {
            throw new \Exception(json_encode(Db::name('dy_accesstoken')->getErrors(), JSON_UNESCAPED_UNICODE));
        }
    }

    //刷新token
    public function refreshToken($authAccount) {
        $arr = [
            'client_key' => $this->client_key,
            'grant_type' => 'refresh_token',
            'refresh_token' => $authAccount['refresh_token'],
        ];
        $response = file_get_contents(self::URL_REFRESH_TOKEN . '?' . http_build_query($arr));
        $data = self::checkResponse($response);
        $authAccount['token_expire_time'] = $data['expires_in'];
        if (!Db::name('dy_accesstoken')->update($authAccount)) {
            throw new \Exception(json_encode(Db::name('dy_accesstoken')->getErrors(), JSON_UNESCAPED_UNICODE));
        }
    }

    //获取token
    public function getTokenByCode($code) {
        $arr = [
            'client_key' => $this->client_key,
            'client_secret' => $this->client_secret,
            'code' => $code,
            'grant_type' => 'authorization_code',
        ];
        //echo self::URL_TOKEN . '?' . http_build_query($arr);
        $response = file_get_contents(self::URL_TOKEN . '?' . http_build_query($arr));
        $data = self::checkResponse($response);
        return $data;
    }

    public function getAuthUserInfo($access_token, $open_id) {
        $arr = [
            'access_token' => $access_token,
            'open_id' => $open_id,
        ];
        $response = file_get_contents(self::URL_USER_INFO . '?' . http_build_query($arr));
        $data = self::checkResponse($response);
        return $data;
    }

    //发布
    public function publishItem($authAccount, $authItem) {
        //大于6M用分片上传,否则用普通上传
        // if ($authItem['size'] > 6000000) {
        //     $data = $this->uploadPart($authAccount, $authItem);
        // } else {
            $data = $this->upload($authAccount, $authItem);
        //}
        $video_id = $data['video']['video_id'];
        $query_arr = [
            'open_id' => $authAccount['open_id'],
            'access_token' => $authAccount['token'],
        ];
        $body = json_encode([
            'video_id' => $video_id,
            'text' => $authItem['text'],
            'micro_app_id' => (isset($authItem['micro_app_id']))?$authItem['micro_app_id']:"", //小程序id
            'poi_id' => (isset($authItem['poi_id']))?$authItem['poi_id']:"", //地理位置id
            'poi_name' => (isset($authItem['poi_name']))?$authItem['poi_name']:"", //地理位置名称
            'micro_app_title' => (isset($authItem['micro_app_title']))?$authItem['micro_app_title']:"", //小程序标题
            'micro_app_url' => (isset($authItem['micro_app_url']))?$authItem['micro_app_url']:"", //	吊起小程序时的url参数
                ], JSON_UNESCAPED_UNICODE);
        $response = Tools::http_post_json(self::URL_VIDEO_CREATE . '?' . http_build_query($query_arr), $body);
        $data = self::checkResponse($response[1]);
        return $data;
    }

    //普通上传
    private function upload($authAccount, $video) {
        $query_arr = [
            'open_id' => $authAccount['open_id'],
            'access_token' => $authAccount['token'],
        ];
        $Video_range=new Video_range();
       // $content = $Video_range->getPartData($video['path'], 0, 6000000);
        $content = file_get_contents($video['path']);
        $body_arr = Tools::buildDouyinUploadData($content);

        $response = Tools::postUploadData(
                        self::URL_VIDEO_UPLOAD . '?' . http_build_query($query_arr),
                        $body_arr['data'],
                        0,
                        ['Content-Type:multipart/form-data;boundary=' . $body_arr['boundary']]
        );
        $data = self::checkResponse($response);
        return $data;
    }

    //分片上传
    private function uploadPart($authAccount, $video) {
        $query_arr = [
            'open_id' => $authAccount['open_id'],
            'access_token' => $authAccount['token'],
        ];
        $body = '';

        $response = Tools::http_post_json(self::URL_VIDEO_UPLOAD_PART_INIT . '?' . http_build_query($query_arr), $body);
        $data = self::checkResponse($response);
        $upload_id = $data['upload_id'];
        $part = 1;
        $part_size = 6000000;
        while ($part) {
            $start = ($part - 1) * $part_size;
            if ($start >= $video['size']) {
                break;
            }

            //如果剩余不足一个分片则一并上传
            $yu = $video['size'] - $start - $part_size;
            if ($yu < $part_size) {
                $part_size += $yu;
            }
            $content = Video_range::getPartData($video['path'], $start, $part_size);
            $body_arr = Tools::buildDouyinUploadData($content);

            $query_arr = [
                'open_id' => $authAccount['open_id'],
                'access_token' => $authAccount['token'],
                'upload_id' => $upload_id,
                'part_number' => $part,
            ];

            $response = Tools::postUploadData(
                            self::URL_VIDEO_UPLOAD_PART_UPLOAD . '?' . http_build_query($query_arr),
                            $body_arr['data'],
                            0,
                            [
                                'Content-Type:multipart/form-data;boundary=' . $body_arr['boundary'],
                            ]
            );
            $data2 = self::checkResponse($response);
            $part++;
        }
        $query_arr = [
            'open_id' => $authAccount['open_id'],
            'access_token' => $authAccount['token'],
            'upload_id' => $upload_id,
        ];

        $response = Tools::http_post_json(self::URL_VIDEO_UPLOAD_PART_COMPLETE . '?' . http_build_query($query_arr));
        $data = self::checkResponse($response);
        return $data;
    }

    //检测并格式化抖音返回数据
    static public function checkResponse($response) {
        $arr = json_decode($response, 1);
        if (empty($arr))
            throw new \Exception('抖音接口返回错误', 20000);
        $data = $arr['data'];
        if (!isset($data['error_code']))
            throw new \Exception('抖音接口返回错误', 20000);
        if ($data['error_code'] != 0) {
            throw new \Exception('抖音接口返回错误:' . $data['error_code'] . ":" . $data['description'], 20000);
        }
        return $data;
    }

}
